#include "<SampleEd$Dir>.h.Driver"
#include "sndfile.h"
#include "kernel.h"
#include "wimp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Import MP3 file */

osbool driver_import(char *filename,int filetype,int size)
    {
    SNDFILE *sndfile;     /* libsndfile handle     */

    SF_INFO wfinfo;       /* File format info      */

    int channelindex,     /* Channel counter       */
        count,            /* Counter               */
        error,            /* Error number          */
        format,           /* Default format number */
        index,            /* Index into sample     */
        out_index,
        default_channels,
        default_samplerate,
        lastpc = 0,       /* Previous percentge    */
        pc;               /* Calculated percentage */

    _kernel_swi_regs r;

    int old_next_slotsize,
        new_next_slotsize;

    int data[32];         /* Channel data          */

    double sample_time;   /* Calculated time       */

    short out[8192];      /* Output buffer         */

    char lame_command[1024];

    char *lame_size,
         *lame_decode;

    FILE *fh;             /* File handle           */

    char tmpname[L_tmpnam];

/* Check that LAME can be found */

    if ((fh = fopen("Run:LAME","r")) == NULL)
        {
        driver_report_error("DrvErrLAME");
        return TRUE;
        }

    if ((fh = fopen(filename,"r")) == NULL)
        {
        driver_report_error("DrvErrOpen");
        return TRUE;
        }

    fclose(fh);

/* Run LAME command to decode file to WAV */

    tmpnam(tmpname);

    new_next_slotsize = 2048 * 1024;

    lame_size = getenv("SampleEd$LAMESlotSize");

    if (lame_size != NULL && atoi(lame_size) > new_next_slotsize)
        {
        new_next_slotsize = atoi(lame_size);
        }

/* Get old next slot size */

    r.r[0] = -1;
    r.r[1] = -1;

    _kernel_swi(Wimp_SlotSize,&r,&r);

    old_next_slotsize = r.r[1];

/* Set our next slot size */

    r.r[1] = new_next_slotsize;

    _kernel_swi(Wimp_SlotSize,&r,&r);

    if (r.r[1] < new_next_slotsize)
        {
        driver_report_error("DrvTaskMem");
        r.r[1] = old_next_slotsize;
        _kernel_swi(Wimp_SlotSize,&r,&r);
        return TRUE;
        }

/* Run task */

    lame_decode = getenv("SampleEd$LAMEDecode");

    if (lame_decode == NULL)
        {
        lame_decode = "";
        }

    sprintf(lame_command,"lame --decode --mp3input --silent %s \"%s\" %s { > null: }",lame_decode,filename,tmpname);

    if (wimp_start_task(lame_command))
        {
        driver_report_error("DrvTask");
        r.r[1] = old_next_slotsize;
        _kernel_swi(Wimp_SlotSize,&r,&r);
        return TRUE;
        }

/* Reset slot size */

    r.r[1] = old_next_slotsize;
    _kernel_swi(Wimp_SlotSize,&r,&r);

    if (!driver_get_defaults(&default_samplerate,
                             &default_channels,
                             &format))
        {
        sndfile = sf_open(tmpname,SFM_READ,&wfinfo);

        error = sf_error(sndfile);
        }
    else
        {
        error = 1;
        }

    if (error)
        {

/* Try using defaults */

        wfinfo.samplerate = default_samplerate;
        wfinfo.channels = default_channels;

        switch (format)
            {
            case DRIVER_IMPORT_PCM_U8:
                wfinfo.format = SF_FORMAT_PCM_U8;
                break;

            case DRIVER_IMPORT_PCM_S8:
                wfinfo.format = SF_FORMAT_PCM_S8;
                break;

            case DRIVER_IMPORT_PCM_16:
                wfinfo.format = SF_FORMAT_PCM_16;
                break;

            case DRIVER_IMPORT_PCM_24:
                wfinfo.format = SF_FORMAT_PCM_24;
                break;

            case DRIVER_IMPORT_PCM_32:
                wfinfo.format = SF_FORMAT_PCM_32;
                break;

            case DRIVER_IMPORT_ULAW:
                wfinfo.format = SF_FORMAT_ULAW;
                break;

            case DRIVER_IMPORT_ALAW:
                wfinfo.format = SF_FORMAT_ALAW;
                break;

            case DRIVER_IMPORT_GSM610:
                wfinfo.format = SF_FORMAT_GSM610;
                break;

            case DRIVER_IMPORT_32_FLOAT:
                wfinfo.format = SF_FORMAT_FLOAT;
                break;

            case DRIVER_IMPORT_64_FLOAT:
                wfinfo.format = SF_FORMAT_DOUBLE;
                break;

            case DRIVER_IMPORT_12_DWVW:
                wfinfo.format = SF_FORMAT_DWVW_12;
                break;

            case DRIVER_IMPORT_16_DWVW:
                wfinfo.format = SF_FORMAT_DWVW_16;
                break;

            case DRIVER_IMPORT_24_DWVW:
                wfinfo.format = SF_FORMAT_DWVW_24;
                break;

            case DRIVER_IMPORT_VOX_ADPCM:
                wfinfo.format = SF_FORMAT_VOX_ADPCM;
                break;
            }

        wfinfo.format |= SF_FORMAT_RAW;

        sndfile = sf_open(tmpname,SFM_READ,&wfinfo);

/* Report an error */

        error = sf_error(sndfile);

        if (error)
            {
            driver_report_error((char *)sf_error_number(error));
            remove(tmpname);
            return TRUE;
            }
        }

/* Read data */

    if (sndfile != NULL)
        {
        driver_set_driver_id(wfinfo.format & SF_FORMAT_TYPEMASK,
                             wfinfo.format & SF_FORMAT_SUBMASK);

/* Calculate sample time */

        sample_time = 100.0 *
                      wfinfo.frames /
                      wfinfo.samplerate;

        driver_set_sample_details(wfinfo.samplerate,
                                  (int)sample_time,
                                  wfinfo.channels,
                                  16);

/* Loop round data */

        index = 0;

        while (index < wfinfo.frames)
            {
/* Calculate percentage */

            pc = 100 * index / wfinfo.frames;

/* Only set percentage if different */

            if (pc > lastpc)
                {
                driver_percentage(pc);
                lastpc = pc;
                }

            out_index = 0;

            while ((index + out_index) < wfinfo.frames &&
                   out_index < (sizeof(out) / 2 / wfinfo.channels))
                {
/* Read input */

                count = sf_read_int(sndfile,data,wfinfo.channels);

/* Check for error */

                error = sf_error(sndfile);

                if (error)
                    {
                    driver_report_error((char *)sf_error_number(error));
                    break;
                    }

/* Loop round each channel */

                for (channelindex = 0;
                     channelindex < wfinfo.channels;
                     channelindex++)
                    {
                    out[out_index * wfinfo.channels + channelindex] = data[channelindex] >> 16;
                    }

                out_index++;
                }

            if (driver_set_sample_block(index * wfinfo.channels,
                                        out,
                                        out_index * wfinfo.channels))
                {
                sf_close(sndfile);
                remove(tmpname);
                return TRUE;
                }

            index += out_index;
            }

        sf_close(sndfile);

        remove(tmpname);
        return FALSE;
        }

    remove(tmpname);
    return FALSE;
    }


/* Set up list of known file types */

DriverFileType *driver_filetypes(void)
    {
    static DriverFileType filetypes[2];

    filetypes[0].id = 0;
    filetypes[0].filetype = 0x1ad;
    strcpy(filetypes[0].suffix,"mp3");
    strcpy(filetypes[0].description,"MP3 (LAME)");

    filetypes[1].id = 1;
    filetypes[1].filetype = 0;
    filetypes[1].suffix[0] = '\0';
    filetypes[1].description[0] = '\0';

    return filetypes;
    }


/* Return list of sub file types */

DriverSubFileType *driver_subfiletypes(int id)
    {
    static DriverSubFileType filetypes[2];

    NOT_USED(id);

    filetypes[0].id = 1;
    strcpy(filetypes[0].description,"Layer 3");

    filetypes[1].id = 0;
    filetypes[1].description[0] = '\0';

    return filetypes;
    }
